#ifndef QLSAVDECODE_H
#define QLSAVDECODE_H

#define VIDEO_PICTURE_QUEUE_SIZE     1
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio

#define MAX_AUDIO_SIZE (25 * 16 * 1024)
#define MAX_VIDEO_SIZE (18 * 256 * 1024)

#include <QObject>
#include <QThread>
#include <QString>
#include <QImage>
#include <QMutex>
#include <QSemaphore>
#include <QPaintEvent>
#include <QtConcurrent>
#include <QFuture>

#include "qls_av_player_global.h"
#include "qls_av_packet_queue.h"

class QLsAVPlayer;
class QLsAVParam;

/// 根据解码后的视频数据 计算出视频的pts
double SynchronizeVideo(QLsAVParam *avParam, AVFrame *srcFrame, double pts);
/**
 * @brief RaiseVolume	音量调节
 * @param buf			需要调节音量的音频数据块首地址指针
 * @param size			长度
 * @param uRepeat		重复次数，通常设为1
 * @param vol			增益倍数,可以小于1
 */
void RaiseVolume(char *buf, int size, int uRepeat, double vol);
/// 视频解码线程
int VDecodeThread(void *arg);
/// 音频回调函数
void ACallback(void *userdata, Uint8 *stream, int len);
/// 音频解码函数
int ADecode(QLsAVParam *avParam);

///< 音视频处理参数封装
class QLS_AV_PLAYER_EXPORT QLsAVParam
{
public:
    QLsAVParam(QLsAVPlayer *avPlayer = nullptr);
    ~QLsAVParam();

    ///< 参数重置
    void ResetParam();

public:
    // 音视频整体
    AVFormatContext *m_inputCtx{ nullptr };
    QLsAVPlayer *m_avPlayer{ nullptr };
    bool m_bDecodeThreadFinished; ///< 解码线程完毕
    bool m_bDecodeFinished;       ///< 解码完毕
    bool m_bQuit;                 ///< 整体退出
    bool m_bPause;                ///< 暂停
    bool m_bMute;                 ///< 静音
    int m_bSeek;                  ///< 跳转标志
    int64_t m_seekPos;            ///< 跳转的位置(微秒)
    double m_seekTime;   ///< 跳转的时间(秒)(值为：m_seekPos / 1e6)
    quint64 m_startTime; ///< 开始播放视频的时间
    quint64 m_pauseStartTime; ///< 暂停开始的时间
    bool m_bFirstPause; ///< 第一次显示是否暂停(为了加载完视频有个预览界面)

    ///< 视频
    int m_vStreamIndex;                       ///< 视频里位置
    AVCodecContext *m_vCodecCtx{ nullptr };   ///< 视频流信息
    AVCodec *m_vCodec{ nullptr };             ///< 视频流解码器
    AVStream *m_vStream{ nullptr };           ///< 视频流
    QLsAVPacketQueue *m_vPktQueue{ nullptr }; ///< 视频数据包缓冲区队列
    QFuture<void> m_vDecodeThread;            ///< 视频解码线程
    bool m_bVDecodeThreadFinished; ///< 视频解码线程是否完成
    double m_vClock;               ///< 视频时钟
    bool m_bVSeek;                 ///< 视频跳转标志

    ///< 音频
    int m_aStreamIndex;                       ///< 音频流位置
    AVCodecContext *m_aCodecCtx{ nullptr };   ///< 音频流信息
    AVCodec *m_aCodec{ nullptr };             ///< 音频流解码器
    AVStream *m_aStream{ nullptr };           ///< 音频流
    QLsAVPacketQueue *m_aPktQueue{ nullptr }; ///< 音频数据包缓冲队列
    AVPacket m_aPacket;                       ///< 音频数据包
    bool m_bADecodeThreadFinished;        ///< 音频解码线程是否完成
    AVFrame *m_aFrame{ nullptr };         ///< 解码出的音频数据
    float m_volume;                       ///< 音量增益系数
    double m_aClock;                      ///< 音频时钟
    bool m_bASeek;                        ///< 音频跳转标志
    AVFrame *m_aFrameReSample{ nullptr }; ///< 重采样后的解码音频数据
    SwrContext *m_aSwrCtx{ nullptr }; ///< 用于解码后的音频格式转换

    // 音频解码
    unsigned int audio_buf_size;
    unsigned int audio_buf_index;
    uint8_t *audio_pkt_data{ nullptr };
    int audio_pkt_size;
    uint8_t *audio_buf{ nullptr };
    DECLARE_ALIGNED(16, uint8_t, audio_buf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
    AVSampleFormat audio_src_fmt;
    AVSampleFormat audio_tgt_fmt;
    int audio_src_channels;
    int audio_tgt_channels;
    int64_t audio_src_channel_layout;
    int64_t audio_tgt_channel_layout;
    int audio_src_freq;
    int audio_tgt_freq;
    int audio_hw_buf_size;

    // 重采样
    AVSampleFormat in_sample_fmt;  ///< 输入的采样格式
    AVSampleFormat out_sample_fmt; ///< 输出的采样格式 16bit PCM
    int in_sample_rate;            ///< 输入的采样率
    int out_sample_rate;           ///< 输出的采样率
    int in_ch_layout;
    int out_ch_layout;
};

/// 音视频解码
class QLS_AV_PLAYER_EXPORT QLsAVPlayer : public QObject
{
    Q_OBJECT
public:
    /// 播放状态
    enum QLsPlayerStatus
    {
        Player_Default = 0, ///< 默认
        Player_Playing,     ///< 播放中
        Player_Pause,       ///< 暂停
        Player_Stop         ///< 停止
    };

public:
    QLsAVPlayer(QObject *parent = nullptr);
    ~QLsAVPlayer();

    /* ---------- 多线程信号槽 ---------- */
    /// 加载
    void Load();
    /// 显示一帧图像
    void DisplayVideo(QImage img);
    /// 重新播放
    bool Replay();
    /// 播放
    bool Play();
    /// 暂停
    bool Pause();
    /// 停止
    bool Stop(bool bWait = false);
    /// 跳转(微秒)
    void Seek(qint64 pos);
    /// 静音
    bool mute() const;
    void setMute(const bool &bMute);
    /// 音量
    void SetVolume(const float &volume);

    /// 路径
    QString AVUrl() const;
    void setAVUrl(const QString &AVUrl);

    /// 音视频播放状态
    QLsPlayerStatus playerStatus() const;

    /// 播放进度/当前时间
    qint64 curTime() const;

    /// 总时长
    qint64 totalTime() const;

    /// 设置是否显示预览(第一次加载视频是否暂停)
    void setPreview(const bool &bFirstPause);

signals:
    /// 获取一帧图像 的信号
    void sigGetOneFrame(QImage);
    /// 状态变化 的信号
    void sigStatusChange(QLsPlayerStatus);
    /// 视频时长变化 的信号
    void sigTotalTimeChange(qint64);

private:
    /// 解码开始
    void DecodeStart();
    /// 解码结束
    void DecodeEnd();
    /**
     * SDL打开音频设备
     * 打开SDL，并设置播放的格式为：AUDIO_S16LSB、双声道、44100Hz
     * 后期使用 ffmpeg
     * 解码完音频后，需要重采样成和这个一样的格式，否则播放会有杂音
     */
    bool SDLOpenADevice();
    /// SDL关闭音频设备
    void SDLCloseADevice();
    /// 打开要解码的音视频流
    bool AVOpenInput(const QString &url);
    /// 获取音视频流的位置信息
    void AVGetStreamIndex();
    /// 获取音频流信息
    bool AVGetAStreamParam();
    /// 获取视频流信息
    bool AVGetVStreamParam();
    /// 解码跳转
    void AVDecodeSeek();
    /// 解码
    void Decoding();

private slots:
    /* ---------- 多线程信号槽 ---------- */
    /// 加载 的槽函数
    void slotLoad();

signals:
    /* ---------- 多线程信号槽 ---------- */
    /// 加载 的信号
    void sigLoad();

private:
    QThread *m_thread{ nullptr };
    QString m_AVUrl;                  ///< 路径
    QLsAVParam *m_avParam{ nullptr }; ///< 音视频处理参数封装
    QLsPlayerStatus m_playerStatus;   ///< 音视频播放状态
    SDL_AudioDeviceID m_aDeviceID;    ///< 音频设备id
};

#endif // QLSAVDECODE_H
